package com.todo.biz.application.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.todo.biz.application.convert.CollectConvert;
import com.todo.biz.application.entity.bo.CollectSetBO;
import com.todo.biz.application.entity.condition.CollectSetConditionBO;
import com.todo.biz.application.service.CollectRelationService;
import com.todo.biz.application.service.CollectSetService;
import com.todo.biz.common.base.BizBaseKeyBuild;
import com.todo.biz.common.enums.CollectSetTypeEnum;
import com.todo.biz.infrastructure.entity.condition.CollectSetCondition;
import com.todo.biz.infrastructure.entity.po.CollectSetPO;
import com.todo.biz.infrastructure.repository.CollectSetRepository;
import com.todo.common.common.entity.response.page.PageResult;
import com.todo.common.common.enums.BizErrorCodeEnum;
import com.todo.common.common.enums.EnableTypeEnum;
import com.todo.common.common.exception.BizException;
import com.todo.common.utils.StringUtils;
import com.todo.component.redis.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * (CollectSet)表服务实现类
 *
 * @author zhangwenxiang
 * @since 2024-03-04 00:19:45
 */
@Slf4j
@Service("collectSetService")
public class CollectSetServiceImpl implements CollectSetService {

    @Resource
    private CollectSetRepository collectSetRepository;
    @Resource
    private CollectRelationService collectRelationService;
    @Resource
    private RedisService redisService;

    @Override
    public Boolean insertCollectSet(CollectSetBO collectSetBO) {
        if (collectSetBO == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        CollectSetBO codeCollectSetBO = queryCollectSetByCode(collectSetBO.getCity(), collectSetBO.getCode());
        if (codeCollectSetBO != null) {
            throw new BizException(BizErrorCodeEnum.SUCCESS_EXIST, "编码已存在");
        }
        CollectSetBO alreadyCollectSetBO = queryCollectSetByTitle(collectSetBO.getTitle());
        if (alreadyCollectSetBO != null) {
            throw new BizException(BizErrorCodeEnum.SUCCESS_EXIST, "标题已存在");
        }
        //默认禁用
        collectSetBO.setStatus(EnableTypeEnum.FORBIDDEN);
        CollectSetPO collectSetPO = CollectConvert.convertToCollectSetPO(collectSetBO);
        Boolean insert = collectSetRepository.insertCollectSetPO(collectSetPO);
        if (insert) {
            String collectCityKey = BizBaseKeyBuild.getCollectCityKey(collectSetBO.getCity());
            redisService.hSet(collectCityKey, collectSetBO.getCode(), JSONObject.toJSONString(collectSetBO));
        }
        return insert;
    }

    public CollectSetBO queryCollectSetByCode(String city, String code) {
        if (StringUtils.isBlank(code)) {
            return null;
        }
        String cityKey = BizBaseKeyBuild.getCollectCityKey(city);
        String cachedValue = redisService.hGet(cityKey, code);
        if (StringUtils.isNotBlank(cachedValue)) {
            return JSONObject.parseObject(cachedValue, CollectSetBO.class);
        }
        CollectSetPO collectSetPO = collectSetRepository.queryCollectSetByCode(code);
        if (collectSetPO == null) {
            return null;
        }
        CollectSetBO collectSetBO = CollectConvert.convertToCollectSetBO(collectSetPO);
        redisService.hSet(cityKey, code, JSONObject.toJSONString(collectSetBO));
        return collectSetBO;
    }

    private CollectSetBO queryCollectSetByTitle(String title) {
        if (StringUtils.isBlank(title)) {
            return null;
        }
        CollectSetPO collectSetPO = collectSetRepository.queryCollectSetByTitle(title);
        return CollectConvert.convertToCollectSetBO(collectSetPO);
    }

    @Override
    public Boolean removeCollectSetById(Long id) {
        if (id == null || id < 0) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        CollectSetBO collectSetBO = queryCollectSetById(id);
        if (collectSetBO == null) {
            return true;
        }
        Boolean removed = collectSetRepository.removeCollectSetPOById(id);
        if (removed) {
            redisService.hDel(BizBaseKeyBuild.getCollectCityKey(collectSetBO.getCity()), collectSetBO.getCode());
            collectRelationService.removeCollectRelationBySetId(id);
        }
        return removed;
    }

    @Override
    public Boolean updateCollectSet(CollectSetBO collectSetBO) {
        if (collectSetBO == null || collectSetBO.getId() == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        CollectSetBO alreadyCollectSetBO = queryCollectSetById(collectSetBO.getId());
        if (alreadyCollectSetBO == null) {
            log.warn("CollectSetService#updateCollectSet 更新集合信息失败，根据主键id查询数据为空 不做修改 collectSetBO：【{}】", JSONObject.toJSONString(collectSetBO));
            return false;
        }
        if (alreadyCollectSetBO.getStatus().equals(EnableTypeEnum.ENABLE)) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "已启用的收藏集合不允许修改");
        }
        //名称不一样时候进行校验
        if (!alreadyCollectSetBO.getTitle().equals(collectSetBO.getTitle())) {
            CollectSetBO collectSetByTitle = queryCollectSetByTitle(collectSetBO.getTitle());
            if (collectSetByTitle != null) {
                throw new BizException(BizErrorCodeEnum.SUCCESS_EXIST, "标题已存在");
            }
        }
        if (!alreadyCollectSetBO.getCode().equals(collectSetBO.getCode())) {
            throw new BizException(BizErrorCodeEnum.SUCCESS_EXIST, "编码无法修改");
        }
        CollectSetPO collectSetPO = CollectConvert.convertToCollectSetPO(collectSetBO);
        Boolean updated = collectSetRepository.updateCollectSetPOById(collectSetPO);
        if (updated) {
            String collectCityKey = BizBaseKeyBuild.getCollectCityKey(collectSetBO.getCity());
            redisService.hDel(collectCityKey, collectSetBO.getCode());
        }
        return updated;
    }

    @Override
    public CollectSetBO queryCollectSetById(Long id) {
        if (id == null || id < 0) {
            return null;
        }
        return CollectConvert.convertToCollectSetBO(collectSetRepository.queryCollectSetPOById(id));
    }

    @Override
    public List<CollectSetBO> queryCollectSetByCity(String city, CollectSetTypeEnum collectType) {
        if (StringUtils.isBlank(city)) {
            return Lists.newArrayList();
        }
        String collectCityKey = BizBaseKeyBuild.getCollectCityKey(city);
        Map<String, String> cacheMap = redisService.hGetAll(collectCityKey);
        List<CollectSetBO> result = new ArrayList<>();
        if (MapUtils.isNotEmpty(cacheMap)) {
            for (String code : cacheMap.keySet()) {
                CollectSetBO collectSetBO = JSONObject.parseObject(cacheMap.get(code), CollectSetBO.class);
                if (collectSetBO != null && collectSetBO.getCollectType().equals(collectType)) {
                    result.add(collectSetBO);
                }
            }
            return result;
        }
        List<CollectSetPO> allCitySetList = collectSetRepository.queryCollectSetByCity(city, null);
        if (CollectionUtils.isEmpty(allCitySetList)) {
            return Collections.emptyList();
        }
        List<CollectSetBO> collect = allCitySetList.stream().map(CollectConvert::convertToCollectSetBO).collect(Collectors.toList());
        for (CollectSetBO collectSetBO : collect) {
            redisService.hSet(collectCityKey, collectSetBO.getCode(), JSONObject.toJSONString(collectSetBO));
        }
        return collect;
    }

    @Override
    public PageResult<CollectSetBO> queryCollectSetByCondition(CollectSetConditionBO conditionBO) {
        if (conditionBO == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        CollectSetCondition condition = CollectConvert.convertToCollectSetCondition(conditionBO);
        PageResult<CollectSetPO> pageResult = collectSetRepository.queryCollectSetByCondition(condition);
        if (pageResult == null || CollectionUtils.isEmpty(pageResult.getResults())) {
            return new PageResult<>(Lists.newArrayList(), conditionBO.getPageIndex(), conditionBO.getPageSize(), 0L);
        }
        PageResult<CollectSetBO> result = new PageResult<>();
        result.setPageNum(pageResult.getPageNum());
        result.setResults(pageResult.getResults().stream().map(CollectConvert::convertToCollectSetBO).collect(Collectors.toList()));
        result.setTotal(pageResult.getTotal());
        result.setPageCount(pageResult.getPageCount());
        result.setCurrentIndex(pageResult.getCurrentIndex());
        return result;
    }

    @Override
    public Boolean enableCollectSetById(Long id, Boolean enable) {
        if (id == null || id < 0) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        CollectSetBO collectSetBO = queryCollectSetById(id);
        if (collectSetBO == null) {
            return false;
        }
        EnableTypeEnum after = enable ? EnableTypeEnum.ENABLE : EnableTypeEnum.FORBIDDEN;
        if (after.equals(collectSetBO.getStatus())) {
            return true;
        }
        Boolean enabled = collectSetRepository.enableCollectSetById(id, after.getType());
        if (enabled) {
            collectSetBO.setStatus(after);
            String collectCityKey = BizBaseKeyBuild.getCollectCityKey(collectSetBO.getCity());
            redisService.hSet(collectCityKey, collectSetBO.getCode(), JSONObject.toJSONString(collectSetBO));
        }
        return enabled;
    }
}
